/// 排序方向枚举
enum Direction {
  /// 升序
  asc,

  /// 降序
  desc,
}

/// 排序字段
class Order {
  /// 字段名
  final String property;

  /// 排序方向
  final Direction direction;

  const Order(this.property, this.direction);

  /// 创建升序排序
  factory Order.asc(String property) {
    return Order(property, Direction.asc);
  }

  /// 创建降序排序
  factory Order.desc(String property) {
    return Order(property, Direction.desc);
  }

  /// 是否为升序
  bool get isAscending => direction == Direction.asc;

  /// 是否为降序
  bool get isDescending => direction == Direction.desc;

  /// 反转排序方向
  Order reverse() {
    return Order(
      property,
      direction == Direction.asc ? Direction.desc : Direction.asc,
    );
  }

  @override
  String toString() {
    return '$property ${direction.name.toUpperCase()}';
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Order &&
          runtimeType == other.runtimeType &&
          property == other.property &&
          direction == other.direction;

  @override
  int get hashCode => property.hashCode ^ direction.hashCode;
}

/// 排序对象
class Sort {
  /// 排序字段列表
  final List<Order> orders;

  const Sort(this.orders);

  /// 创建无排序
  const Sort.unsorted() : orders = const [];

  /// 创建单字段升序排序
  factory Sort.by(String property) {
    return Sort([Order.asc(property)]);
  }

  /// 创建单字段降序排序
  factory Sort.byDesc(String property) {
    return Sort([Order.desc(property)]);
  }

  /// 创建多字段排序
  factory Sort.byProperties(
    List<String> properties, [
    Direction direction = Direction.asc,
  ]) {
    final orders = properties.map((prop) => Order(prop, direction)).toList();
    return Sort(orders);
  }

  /// 创建自定义排序
  factory Sort.byOrders(List<Order> orders) {
    return Sort(orders);
  }

  /// 添加排序字段（升序）
  Sort and(String property) {
    return Sort([...orders, Order.asc(property)]);
  }

  /// 添加排序字段（降序）
  Sort andDesc(String property) {
    return Sort([...orders, Order.desc(property)]);
  }

  /// 添加排序Order
  Sort andOrder(Order order) {
    return Sort([...orders, order]);
  }

  /// 反转所有排序方向
  Sort reverse() {
    return Sort(orders.map((order) => order.reverse()).toList());
  }

  /// 是否为空排序
  bool get isEmpty => orders.isEmpty;

  /// 是否非空排序
  bool get isNotEmpty => orders.isNotEmpty;

  /// 获取排序字段数量
  int get length => orders.length;

  /// 获取第一个排序字段
  Order? get firstOrder => orders.isNotEmpty ? orders.first : null;

  /// 获取指定字段的排序
  Order? getOrderFor(String property) {
    try {
      return orders.firstWhere((order) => order.property == property);
    } catch (e) {
      return null;
    }
  }

  /// 是否包含指定字段的排序
  bool isSorted(String property) {
    return getOrderFor(property) != null;
  }

  /// 转换为SQL ORDER BY子句
  String toSql() {
    if (isEmpty) {
      return '';
    }
    return orders.map((order) => order.toString()).join(', ');
  }

  @override
  String toString() {
    if (isEmpty) {
      return 'UNSORTED';
    }
    return orders.join(', ');
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Sort &&
          runtimeType == other.runtimeType &&
          _listEquals(orders, other.orders);

  @override
  int get hashCode => orders.hashCode;

  /// 比较两个列表是否相等
  bool _listEquals<T>(List<T> a, List<T> b) {
    if (a.length != b.length) return false;
    for (int i = 0; i < a.length; i++) {
      if (a[i] != b[i]) return false;
    }
    return true;
  }
}

/// Sort扩展方法
extension SortExtension on Sort {
  /// 创建组合排序
  Sort then(Sort other) {
    return Sort([...orders, ...other.orders]);
  }

  /// 添加多个字段排序
  Sort andAll(List<String> properties, [Direction direction = Direction.asc]) {
    final newOrders = properties.map((prop) => Order(prop, direction)).toList();
    return Sort([...orders, ...newOrders]);
  }

  /// 移除指定字段的排序
  Sort without(String property) {
    final filteredOrders = orders
        .where((order) => order.property != property)
        .toList();
    return Sort(filteredOrders);
  }

  /// 替换指定字段的排序
  Sort replace(String property, Direction direction) {
    final newOrders = orders.map((order) {
      return order.property == property ? Order(property, direction) : order;
    }).toList();
    return Sort(newOrders);
  }
}
